<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <!-- token substitution - in the form $foo -->
    <xsl:param name="substitutions" />
    <xsl:template match="text()[starts-with(.,'$')]">
        <!-- token name in the form $foo -->
        <xsl:variable name="tokname" select="substring(.,2)" />
        <!-- try to find replacement in <replacement><token name="foo" value="bar">...</replacement> -->
        <xsl:variable name="value" select="$substitutions/replacement/token[@name=$tokname]/@value" />
        <xsl:choose>
            <xsl:when test="$value">
                <!-- found - substitute value -->
                <xsl:value-of select="$value" />
            </xsl:when>
            <xsl:otherwise>
                <!-- not found - give parent XSLT a shot at it with templates of the form:
                     <xsl:template mode="default" match="text()[.='$foo']">bar</xsl:template> -->
                <xsl:apply-templates mode="default" select="." />
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <!-- Uncomment the below to spew transformed manifest to the console for debugging -->
    <!--
    <xsl:template match="/">
        <xsl:message terminate="yes">
            <xsl:apply-templates select="*" />
        </xsl:message>
    </xsl:template>
    -->

    <!-- Pass through everything not otherwise matched -->
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*" />
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>
